import csv
import threading
import time

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait


class Transaction:
    def __init__(self, hash_value, method, block, from_addr, from_type, to_addr, to_type, amount):
        self.hash_value = hash_value
        self.method = method
        self.block = block
        self.from_addr = from_addr
        self.from_type = from_type
        self.to_type = to_type
        self.to_addr = to_addr
        self.amount = amount


forward_transactions = []
backward_transactions = []


# 类型1：啥都不带的正常地址
def get_from_type1(tr_element):
    span_element_from = tr_element.find_element(By.XPATH, './td[8]/div/a[1]/span')
    return span_element_from.get_attribute('data-highlight-target')


# 类型2：前面带一个文档图标的正常地址
def get_from_type2(tr_element):
    span_element_from = tr_element.find_element(By.XPATH, './td[8]/div/div/a/span')
    return span_element_from.get_attribute('data-highlight-target')


# 类型3：前面带一个文档图标的合约地址 or 比特币地址
# /html/body/div/div[2]/div[2]/table/tbody/tr[7]/td[8]/div/div/a
# /html/body/div/div[2]/div[2]/table/tbody/tr[23]/td[8]/div/div/a
def get_from_type3(tr_element):
    a_element_from = tr_element.find_element(By.XPATH, './td[8]/div/div/a')
    from_account_url = a_element_from.get_attribute('href')

    # 找最后一个路径
    last_path_index = from_account_url.rfind('/')
    if last_path_index == -1:
        return ""
    last_path = from_account_url[last_path_index:]

    # 如果找到了问号，进行切片
    index = last_path.find('?')
    if index == -1:
        return ""

    return last_path[index + 3:]


get_from_methods = [
    get_from_type1,
    get_from_type2,
    get_from_type3
]


def get_from(tr_element):
    for i, method in enumerate(get_from_methods, start=1):
        try:
            from_account = method(tr_element)
            if from_account == "" or from_account is None:
                continue

            return from_account, i

        except:
            continue

    return None, -1


# 类型1：啥都不带的正常地址
# /html/body/div/div[2]/div[2]/table/tbody/tr[12]/td[10]/div/a[1]/span
def get_to_type1(tr_element):
    span_element_from = tr_element.find_element(By.XPATH, './td[10]/div/a[1]/span')
    return span_element_from.get_attribute('data-highlight-target')


# 类型2：前面带一个文档图标的正常地址
# /html/body/div/div[2]/div[2]/table/tbody/tr[1]/td[10]/div/div/a/span
def get_to_type2(tr_element):
    span_element_from = tr_element.find_element(By.XPATH, './td[10]/div/div/a/span')
    return span_element_from.get_attribute('data-highlight-target')


# 类型3：前面带一个文档图标的合约地址 or 比特币地址
#
# /html/body/div/div[2]/div[2]/table/tbody/tr[24]/td[10]/div/div/span/a
def get_to_type3(tr_element):
    a_element_to = tr_element.find_element(By.XPATH, './td[10]/div/div/span/a')
    to_account_url = a_element_to.get_attribute('href')

    # 找最后一个路径
    last_path_index = to_account_url.rfind('/')
    if last_path_index == -1:
        return ""
    last_path = to_account_url[last_path_index:]

    # 如果找到了问号，进行切片
    index = last_path.find('?')
    if index == -1:
        return ""

    return last_path[index + 3:]


get_to_methods = [
    get_to_type1,
    get_to_type2,
    get_to_type3
]


def get_to(tr_element):
    for i, method in enumerate(get_to_methods, start=1):
        try:
            to_account = method(tr_element)
            if to_account == "" or to_account is None:
                continue

            return to_account, i

        except:
            continue

    return None, -1


# 配置Chrome下载路径
chrome_options = Options()
# chrome_options.add_argument("--headless")  # 启用无头模式
# chrome_options.add_argument("--disable-gpu")  # 禁用GPU
# chrome_options.add_argument("--blink-settings=imagesEnabled=false")  # 禁用图片加载
# chrome_options.add_argument("--disable-extensions")  # 禁用扩展
chrome_options.add_experimental_option("prefs", {
    "download.prompt_for_download": False,
    "download.directory_upgrade": True,
    "safebrowsing.enabled": True
})


def crawl(isForward=True):
    # 启动Chrome浏览器
    driver = webdriver.Chrome(options=chrome_options)

    # 目标网页的URL
    url = 'https://polygonscan.com/token/0x2f800db0fdb5223b3c3f354886d907a671414a7f'  # 替换为实际的网页地址
    driver.get(url)

    if not isForward:
        iframe = WebDriverWait(driver, 8).until(
            EC.presence_of_element_located((By.ID, "tokentxnsiframe"))  # 通过ID定位iframe
        )
        driver.switch_to.frame(iframe)

        # //*[@id="divDataInfo"]/div/div/nav/ul/li[5]/a
        last_button = WebDriverWait(driver, 4).until(
            EC.element_to_be_clickable((By.XPATH, './/a[@class="page-link"]//span[text()="Last"]'))
        )
        last_button.click()

        driver.switch_to.default_content()

    # 开始循环
    for i in range(2000):
        try:
            # time.sleep(4)
            time1 = time.time()
            iframe = WebDriverWait(driver, 8).until(
                EC.presence_of_element_located((By.ID, "tokentxnsiframe"))  # 通过ID定位iframe
            )
            driver.switch_to.frame(iframe)
            time2 = time.time()

            tr_root_element = WebDriverWait(driver, 8).until(
                EC.element_to_be_clickable((By.XPATH, '//*[@id="maindiv"]/div[2]/table/tbody'))
            )

            page_backward_txs = []
            for tr_index in range(1, 26):  # 生成 tr[1] 到 tr[25] 的 XPath
                tr_element = tr_root_element.find_element(By.XPATH, f'.//tr[{tr_index}]')

                # 获取交易hash
                a_element = tr_element.find_element(By.XPATH, './/a[contains(@class, "hash-tag text-truncate")]')
                hash_value = a_element.text
                # print(hash_value)

                # 获取交易方法
                span_element = tr_element.find_element(By.XPATH,
                                                       './/span[contains(@class, "d-block badge bg-light border border-dark dark:border-white border-opacity-10 text-dark fw-normal text-truncate w-100 py-1.5")]')
                method = span_element.text
                # print(method)

                # 获取区块号
                a_element_2 = tr_element.find_element(By.XPATH, './/a[contains(@href, "/block/")]')
                block_number = a_element_2.text
                # print(block_number)

                # 获取from account
                from_account, from_match_type = get_from(tr_element)
                # print(tr_index, from_match_type, from_account)

                # 获得to_account
                to_account, to_match_type = get_to(tr_element)
                # print(tr_index, to_match_type, to_account)

                # 获得amount
                # /html/body/div/div[2]/div[2]/table/tbody/tr[1]/td[11]/span[1]
                span_element_amount = tr_element.find_element(By.XPATH, './td[11]/span[1]')
                amount = span_element_amount.text
                # print(amount)

                tx = Transaction(hash_value, method, block_number, from_account, from_match_type, to_account,
                                 to_match_type,
                                 amount)
                if isForward:
                    forward_transactions.append(tx)
                else:
                    page_backward_txs.append(tx)

            if not isForward:
                backward_transactions[:0]=page_backward_txs

            time3 = time.time()
            # 点击翻页按钮
            if isForward:
                next_button = WebDriverWait(driver, 4).until(
                    EC.element_to_be_clickable((By.XPATH, './/a[@class="page-link px-3" and @aria-label="Next"]'))
                )
                next_button.click()
            else:
                pre_button = WebDriverWait(driver, 4).until(
                    EC.element_to_be_clickable((By.XPATH, './/a[@class="page-link px-3" and @aria-label="Previous"]'))
                )
                pre_button.click()

            time4 = time.time()

            driver.switch_to.default_content()
            time5 = time.time()
            time.sleep(0.1)  # 等待0.1秒

            if isForward:
                print(
                    f"Forward Page {i + 1}/2000 completed. [switch iframe: {time2 - time1:.3f}s]  [get txs: {time3 - time2:.3f}s]  [click next: {time4 - time3:.3f}s]  [switch back iframe: {time5 - time4:.3f}s]  total: {time5 - time1:.3f}s]")
            else:
                print(
                    f"Backward Page {i + 1}/2000 completed. [switch iframe: {time2 - time1:.3f}s]  [get txs: {time3 - time2:.3f}s]  [click next: {time4 - time3:.3f}s]  [switch back iframe: {time5 - time4:.3f}s]  total: {time5 - time1:.3f}s]")

        except Exception as e:
            print(f"Error at page {i + 1}: {str(e)}")
            continue

    driver.quit()


forward_thread = threading.Thread(target=crawl, args=(True,))
backward_thread = threading.Thread(target=crawl, args=(False,))
forward_thread.start()
backward_thread.start()
forward_thread.join()
backward_thread.join()

# 保存交易数据到 CSV 文件
with open('transactions.csv', mode='w', newline='', encoding='utf-8') as file:
    writer = csv.writer(file)
    writer.writerow(['TxHash', 'Method', 'Block', 'From', 'FromType', 'To', 'ToType', 'Amount'])

    forward_transactions.extend(backward_transactions)
    for transaction in forward_transactions:
        writer.writerow([
            transaction.hash_value,
            transaction.method,
            transaction.block,
            transaction.from_addr,
            transaction.from_type,
            transaction.to_addr,
            transaction.to_type,
            transaction.amount
        ])
